package awesome.cpu.structure;

import awesome.cpu.utils.Mode;

public class InstructionRegister extends SequentialComponent{
	
	private InstructionRegister(){}
	
	private static boolean outputDebug = true;
	
	private final static InstructionRegister mInstance = new InstructionRegister();
	
	public static InstructionRegister getInstance(){
		return mInstance;
	}
	
	public final static int KEY_IRWRITE_ENABLE = 1;
	private int mIRWriteEnable;

	public final static int KEY_INSTRUCTION_INPUT = 2;
	private int mInstructionInput;
	private int mInstruction;
	
	public final static int KEY_INSTRUCTION_31_24 = 3;
	private int instruction_31_24;
	
	public final static int KEY_INSTRUCTION_23_19 = 4;
	private int instruction_23_19;
	
	public final static int KEY_INSTRUCTION_23_0 = 5;
	private int instruction_23_0;
	
	public final static int KEY_INSTRUCTION_4_0 = 6;
	private int instruction_4_0;
	
	public final static int KEY_INSTRUCTION_18_14 = 7;
	private int instruction_18_14;
	
	public final static int KEY_INSTRUCTION_13_0 = 8;
	private int instruction_13_0;
	
	public final static int KEY_INSTRUCTION_13_9 = 9;
	private int instruction_13_9;
	
	public final static int KEY_INSTRUCTION_8_5 = 10;
	private int instruction_8_5;
	
	public final static int KEY_INSTRUCTION_8_0 = 11;
	private int instruction_8_0;

	@Override
	int getData(int keyInterface) {
		
		switch(keyInterface){
		
		case KEY_INSTRUCTION_31_24:
			return instruction_31_24;
			
		case KEY_INSTRUCTION_23_19:
			return instruction_23_19;
			
		case KEY_INSTRUCTION_23_0:
			return instruction_23_0;
			
		case KEY_INSTRUCTION_4_0:
			return instruction_4_0;
			
		case KEY_INSTRUCTION_18_14:
			return instruction_18_14;
			
		case KEY_INSTRUCTION_13_0:
			return instruction_13_0;
				
		case KEY_INSTRUCTION_13_9:
			return instruction_13_9;
			
		case KEY_INSTRUCTION_8_5:
			return instruction_8_5;			
			
		case KEY_INSTRUCTION_8_0:
			return instruction_8_0;
		
		}
		
		return 0;
	}

	@Override
	void onClockTick() {
		// if IRWrite enable, write 
		if (mIRWriteEnable == 1){
			
			mInstruction = mInstructionInput;
		}

		calc();
		
		if (outputDebug && Mode.getDebugLevel() >= Mode.DEBUG_LEVEL_PRINT_ALL) {
			System.out.println("IR: Instruction = "+mInstruction);
			//System.out.println("IR: IRWriteEnable = "+mIRWriteEnable);
			//System.out.println("IR: rs1(22~19) = " + instruction_22_19);
			//System.out.println("IR: rs2(4~0) = " + instruction_4_0);
			System.out.println("IR: op(13~9) = " + instruction_13_9);
			System.out.println("IR: op(31~24) = " + instruction_31_24);
		}
	}
	
	private void calc() {
		instruction_31_24 = (mInstruction & 0x0ff000000) >> 24;
		instruction_23_19 = (mInstruction & 0x0f80000) >> 19;
		instruction_23_0 = mInstruction & 0x0ffffff;
		if ((instruction_23_0 & 0x800000) > 0) {
			instruction_23_0 |= 0xff000000;
		}
		instruction_4_0 = mInstruction & 0x0f;
		instruction_18_14 = (mInstruction & 0x07c000) >> 14;
		instruction_13_0 = mInstruction & 0x03fff;
		instruction_13_9 = (mInstruction & 0x1f00) >> 9;
		instruction_8_0 = mInstruction & 0x0ff;
		instruction_8_5 = (mInstruction & 0x01e0) >> 5;
	}

	@Override
	boolean setData(int keyInterface, int data) {
		switch (keyInterface){
		case KEY_IRWRITE_ENABLE:
			mIRWriteEnable = data;
			return true;
		case KEY_INSTRUCTION_INPUT:
			mInstructionInput = data;
			return true;
		}
		return false;
	}
	
	@Override
	public void stop() {
		super.stop();
		if (outputDebug && Mode.getDebugLevel() >= Mode.DEBUG_LEVEL_PRINT_ALL) {
			System.out.println("IR.stop(): Instruction set to 0");
		}
		mInstruction = 0;
		calc();
	}
}
